const SAMPLE_RATE = 16000;
const CHANNELS = 1;
const FRAME_SIZE = 960;  // 对应于60ms帧大小 (16000Hz * 0.06s = 960 samples)
const OPUS_APPLICATION = 2049; // OPUS_APPLICATION_AUDIO
const BUFFER_SIZE = 4096;
const WS_SERVER = "ws://www.hanxiaoxin.cn:4000?device-Id=test&client-Id=test";

let audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: SAMPLE_RATE });
let mediaStream, mediaSource, audioProcessor;
let recordedPcmData = []; // 存储原始PCM数据
let recordedOpusData = []; // 存储Opus编码后的数据
let opusEncoder, opusDecoder;
let isRecording = false;
let isRecordingAndUploading = false;
let wsClient = null;

const startButton = document.getElementById("start");
const stopButton = document.getElementById("stop");
const playButton = document.getElementById("play");
const startAndUploadButton = document.getElementById("startAndUpload");
const downloadWavButton = document.getElementById("downloadWav");
const downloadOpusButton = document.getElementById("downloadOpus");
const statusLabel = document.getElementById("status");
const importOpusBtn = document.getElementById("importOpusBtn");
const importOpusInput = document.getElementById("importOpusInput");
const importStatus = document.getElementById("importStatus");

startButton.addEventListener("click", startRecording);
stopButton.addEventListener("click", stopRecording);
playButton.addEventListener("click", playRecording);
startAndUploadButton.addEventListener("click", startRecordingAndUpload);
downloadWavButton.addEventListener("click", downloadWavFile);
downloadOpusButton.addEventListener("click", downloadOpusFile);

// 添加导入OPUS文件的事件监听器
importOpusBtn.addEventListener("click", () => {
    importOpusInput.click();
});

importOpusInput.addEventListener("change", handleImportOpusFile);

// WebSocket连接函数
async function connectWebSocket() {
    return new Promise((resolve, reject) => {
        try {
            wsClient = new WebSocket(WS_SERVER);

            wsClient.onopen = () => {
                console.log("WebSocket连接成功");
                statusLabel.textContent = "WebSocket已连接，准备录音上传";
                resolve();
            };

            wsClient.onerror = (error) => {
                console.error("WebSocket连接错误:", error);
                statusLabel.textContent = "WebSocket连接失败";
                reject(error);
            };

            wsClient.onclose = () => {
                console.log("WebSocket连接已关闭");
                // statusLabel.textContent = "WebSocket连接已关闭";
            };

            // 设置连接超时
            setTimeout(() => {
                if (wsClient.readyState !== WebSocket.OPEN) {
                    reject(new Error("WebSocket连接超时"));
                }
            }, 5000);

        } catch (error) {
            reject(error);
        }
    });
}

// 初始化Opus编码器与解码器
async function initOpus() {
    if (typeof window.ModuleInstance === 'undefined') {
        if (typeof Module !== 'undefined') {
            // 尝试使用全局Module
            window.ModuleInstance = Module;
            console.log('使用全局Module作为ModuleInstance');
        } else {
            console.error("Opus库未加载，ModuleInstance和Module对象都不存在");
            return false;
        }
    }
    
    try {
        const mod = window.ModuleInstance;
        
        // 创建编码器
        opusEncoder = {
            channels: CHANNELS,
            sampleRate: SAMPLE_RATE,
            frameSize: FRAME_SIZE,
            maxPacketSize: 4000,
            module: mod,
            
            // 初始化编码器
            init: function() {
                // 获取编码器大小
                const encoderSize = mod._opus_encoder_get_size(this.channels);
                console.log(`Opus编码器大小: ${encoderSize}字节`);
                
                // 分配内存
                this.encoderPtr = mod._malloc(encoderSize);
                if (!this.encoderPtr) {
                    throw new Error("无法分配编码器内存");
                }
                
                // 初始化编码器
                const err = mod._opus_encoder_init(
                    this.encoderPtr,
                    this.sampleRate,
                    this.channels,
                    OPUS_APPLICATION
                );
                
                if (err < 0) {
                    throw new Error(`Opus编码器初始化失败: ${err}`);
                }
                
                return true;
            },
            
            // 编码方法
            encode: function(pcmData) {
                const mod = this.module;
                
                // 为PCM数据分配内存
                const pcmPtr = mod._malloc(pcmData.length * 2); // Int16 = 2字节
                
                // 将数据复制到WASM内存
                for (let i = 0; i < pcmData.length; i++) {
                    mod.HEAP16[(pcmPtr >> 1) + i] = pcmData[i];
                }
                
                // 为Opus编码数据分配内存
                const maxEncodedSize = this.maxPacketSize;
                const encodedPtr = mod._malloc(maxEncodedSize);
                
                // 编码
                const encodedBytes = mod._opus_encode(
                    this.encoderPtr,
                    pcmPtr,
                    this.frameSize,
                    encodedPtr,
                    maxEncodedSize
                );
                
                if (encodedBytes < 0) {
                    mod._free(pcmPtr);
                    mod._free(encodedPtr);
                    throw new Error(`Opus编码失败: ${encodedBytes}`);
                }
                
                // 复制编码后的数据
                const encodedData = new Uint8Array(encodedBytes);
                for (let i = 0; i < encodedBytes; i++) {
                    encodedData[i] = mod.HEAPU8[encodedPtr + i];
                }
                
                // 释放内存
                mod._free(pcmPtr);
                mod._free(encodedPtr);
                
                return encodedData;
            },
            
            // 销毁方法
            destroy: function() {
                if (this.encoderPtr) {
                    this.module._free(this.encoderPtr);
                    this.encoderPtr = null;
                }
            }
        };
        
        // 创建解码器
        opusDecoder = {
            channels: CHANNELS,
            rate: SAMPLE_RATE,
            frameSize: FRAME_SIZE,
            module: mod,
            
            // 初始化解码器
            init: function() {
                // 获取解码器大小
                const decoderSize = mod._opus_decoder_get_size(this.channels);
                console.log(`Opus解码器大小: ${decoderSize}字节`);
                
                // 分配内存
                this.decoderPtr = mod._malloc(decoderSize);
                if (!this.decoderPtr) {
                    throw new Error("无法分配解码器内存");
                }
                
                // 初始化解码器
                const err = mod._opus_decoder_init(
                    this.decoderPtr,
                    this.rate,
                    this.channels
                );
                
                if (err < 0) {
                    throw new Error(`Opus解码器初始化失败: ${err}`);
                }
                
                return true;
            },
            
            // 解码方法
            decode: function(opusData) {
                const mod = this.module;
                
                // 为Opus数据分配内存
                const opusPtr = mod._malloc(opusData.length);
                mod.HEAPU8.set(opusData, opusPtr);
                
                // 为PCM输出分配内存
                const pcmPtr = mod._malloc(this.frameSize * 2); // Int16 = 2字节
                
                // 解码
                const decodedSamples = mod._opus_decode(
                    this.decoderPtr,
                    opusPtr,
                    opusData.length,
                    pcmPtr,
                    this.frameSize,
                    0 // 不使用FEC
                );
                
                if (decodedSamples < 0) {
                    mod._free(opusPtr);
                    mod._free(pcmPtr);
                    throw new Error(`Opus解码失败: ${decodedSamples}`);
                }
                
                // 复制解码后的数据
                const decodedData = new Int16Array(decodedSamples);
                for (let i = 0; i < decodedSamples; i++) {
                    decodedData[i] = mod.HEAP16[(pcmPtr >> 1) + i];
                }
                
                // 释放内存
                mod._free(opusPtr);
                mod._free(pcmPtr);
                
                return decodedData;
            },
            
            // 销毁方法
            destroy: function() {
                if (this.decoderPtr) {
                    this.module._free(this.decoderPtr);
                    this.decoderPtr = null;
                }
            }
        };
        
        // 初始化编码器和解码器
        if (opusEncoder.init() && opusDecoder.init()) {
            console.log("Opus 编码器和解码器初始化成功。");
            return true;
        } else {
            console.error("Opus 初始化失败");
            return false;
        }
    } catch (error) {
        console.error("Opus 初始化失败:", error);
        return false;
    }
}

// 将Float32音频数据转换为Int16音频数据
function convertFloat32ToInt16(float32Data) {
    const int16Data = new Int16Array(float32Data.length);
    for (let i = 0; i < float32Data.length; i++) {
        // 将[-1,1]范围转换为[-32768,32767]
        const s = Math.max(-1, Math.min(1, float32Data[i]));
        int16Data[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
    }
    return int16Data;
}

// 将Int16音频数据转换为Float32音频数据
function convertInt16ToFloat32(int16Data) {
    const float32Data = new Float32Array(int16Data.length);
    for (let i = 0; i < int16Data.length; i++) {
        // 将[-32768,32767]范围转换为[-1,1]
        float32Data[i] = int16Data[i] / (int16Data[i] < 0 ? 0x8000 : 0x7FFF);
    }
    return float32Data;
}

function startRecording() {
    if (isRecording) return;
    
    // 确保有权限并且AudioContext是活跃的
    if (audioContext.state === 'suspended') {
        audioContext.resume().then(() => {
            console.log("AudioContext已恢复");
            continueStartRecording();
        }).catch(err => {
            console.error("恢复AudioContext失败:", err);
            statusLabel.textContent = "无法激活音频上下文，请再次点击";
        });
    } else {
        continueStartRecording();
    }
}

// 实际开始录音的逻辑
function continueStartRecording() {
    // 重置录音数据
    recordedPcmData = [];
    recordedOpusData = [];
    window.audioDataBuffer = new Int16Array(0); // 重置缓冲区
    
    // 添加调试计数器
    window.totalPcmSamplesProcessed = 0;
    window.totalOpusFramesEncoded = 0;
    console.log("录音数据已重置，开始新的录音会话");
    
    // 初始化Opus
    initOpus().then(success => {
        if (!success) {
            statusLabel.textContent = "Opus初始化失败";
            return;
        }
        
        console.log("开始录音，参数：", {
            sampleRate: SAMPLE_RATE,
            channels: CHANNELS,
            frameSize: FRAME_SIZE,
            bufferSize: BUFFER_SIZE
        });
        
        // 请求麦克风权限
        navigator.mediaDevices.getUserMedia({ 
            audio: {
                sampleRate: SAMPLE_RATE,
                channelCount: CHANNELS,
                echoCancellation: true,
                noiseSuppression: true,
                autoGainControl: true
            } 
        })
        .then(stream => {
            console.log("获取到麦克风流，实际参数：", stream.getAudioTracks()[0].getSettings());
            
            // 检查流是否有效
            if (!stream || !stream.getAudioTracks().length || !stream.getAudioTracks()[0].enabled) {
                throw new Error("获取到的音频流无效");
            }
            
            mediaStream = stream;
            mediaSource = audioContext.createMediaStreamSource(stream);
            
            // 创建ScriptProcessor(虽然已弃用，但兼容性好)
            // 在降级到ScriptProcessor之前尝试使用AudioWorklet
            createAudioProcessor().then(processor => {
                if (processor) {
                    console.log("使用AudioWorklet处理音频");
                    audioProcessor = processor;
                    // 连接音频处理链
                    mediaSource.connect(audioProcessor);
                    audioProcessor.connect(audioContext.destination);
                } else {
                    console.log("回退到ScriptProcessor");
                    // 创建ScriptProcessor节点
                    audioProcessor = audioContext.createScriptProcessor(BUFFER_SIZE, CHANNELS, CHANNELS);
                    
                    // 处理音频数据
                    audioProcessor.onaudioprocess = processAudioData;
                    
                    // 连接音频处理链
                    mediaSource.connect(audioProcessor);
                    audioProcessor.connect(audioContext.destination);
                }
                
                // 更新UI
                isRecording = true;
                statusLabel.textContent = "录音中...";
                startButton.disabled = true;
                stopButton.disabled = false;
                playButton.disabled = true;
                downloadWavButton.disabled = true;
                downloadOpusButton.disabled = true;
            }).catch(error => {
                console.error("创建音频处理器失败:", error);
                statusLabel.textContent = "创建音频处理器失败";
            });
        })
        .catch(error => {
            console.error("获取麦克风失败:", error);
            statusLabel.textContent = "获取麦克风失败: " + error.message;
        });
    });
}

// 创建AudioWorklet处理器
async function createAudioProcessor() {
    try {
        // 尝试使用更现代的AudioWorklet API
        if ('AudioWorklet' in window && 'AudioWorkletNode' in window) {
            // 定义AudioWorklet处理器代码
            const workletCode = `
                class OpusRecorderProcessor extends AudioWorkletProcessor {
                    constructor() {
                        super();
                        this.buffers = [];
                        this.frameSize = ${FRAME_SIZE};
                        this.buffer = new Float32Array(this.frameSize);
                        this.bufferIndex = 0;
                        this.isRecording = false;
                        
                        this.port.onmessage = (event) => {
                            if (event.data.command === 'start') {
                                this.isRecording = true;
                            } else if (event.data.command === 'stop') {
                                this.isRecording = false;
                                // 发送最后的缓冲区
                                if (this.bufferIndex > 0) {
                                    const finalBuffer = this.buffer.slice(0, this.bufferIndex);
                                    this.port.postMessage({ buffer: finalBuffer });
                                }
                            }
                        };
                    }
                    
                    process(inputs, outputs) {
                        if (!this.isRecording) return true;
                        
                        // 获取输入数据
                        const input = inputs[0][0]; // mono channel
                        if (!input || input.length === 0) return true;
                        
                        // 将输入数据添加到缓冲区
                        for (let i = 0; i < input.length; i++) {
                            this.buffer[this.bufferIndex++] = input[i];
                            
                            // 当缓冲区填满时，发送给主线程
                            if (this.bufferIndex >= this.frameSize) {
                                this.port.postMessage({ buffer: this.buffer.slice() });
                                this.bufferIndex = 0;
                            }
                        }
                        
                        return true;
                    }
                }
                
                registerProcessor('opus-recorder-processor', OpusRecorderProcessor);
            `;
            
            // 创建Blob URL
            const blob = new Blob([workletCode], { type: 'application/javascript' });
            const url = URL.createObjectURL(blob);
            
            // 加载AudioWorklet模块
            await audioContext.audioWorklet.addModule(url);
            
            // 创建AudioWorkletNode
            const workletNode = new AudioWorkletNode(audioContext, 'opus-recorder-processor');
            
            // 处理从AudioWorklet接收的消息
            workletNode.port.onmessage = (event) => {
                if (event.data.buffer) {
                    // 使用与ScriptProcessor相同的处理逻辑
                    processAudioData({
                        inputBuffer: {
                            getChannelData: () => event.data.buffer
                        }
                    });
                }
            };
            
            // 启动录音
            workletNode.port.postMessage({ command: 'start' });
            
            // 保存停止函数
            workletNode.stopRecording = () => {
                workletNode.port.postMessage({ command: 'stop' });
            };
            
            console.log("AudioWorklet 音频处理器创建成功");
            return workletNode;
        }
    } catch (error) {
        console.error("创建AudioWorklet失败，将使用ScriptProcessor:", error);
    }
    
    // 如果AudioWorklet不可用或失败，返回null以便回退到ScriptProcessor
    return null;
}

// 处理音频数据
function processAudioData(e) {
    // 获取输入缓冲区
    const inputBuffer = e.inputBuffer;
    
    // 获取第一个通道的Float32数据
    const inputData = inputBuffer.getChannelData(0);
    
    // 添加调试信息
    const nonZeroCount = Array.from(inputData).filter(x => Math.abs(x) > 0.001).length;
    console.log(`接收到音频数据: ${inputData.length} 个样本, 非零样本数: ${nonZeroCount}`);
    
    // 如果全是0，可能是麦克风没有正确获取声音
    if (nonZeroCount < 5) {
        console.warn("警告: 检测到大量静音样本，请检查麦克风是否正常工作");
        // 继续处理，以防有些样本确实是静音
    }
    
    // 存储PCM数据用于调试
    recordedPcmData.push(new Float32Array(inputData));
    
    // 更新PCM样本计数器
    window.totalPcmSamplesProcessed += inputData.length;
    
    // 转换为Int16数据供Opus编码
    const int16Data = convertFloat32ToInt16(inputData);
    
    // 如果收集到的数据不是FRAME_SIZE的整数倍，需要进行处理
    // 创建静态缓冲区来存储不足一帧的数据
    if (!window.audioDataBuffer) {
        window.audioDataBuffer = new Int16Array(0);
    }
    
    // 合并之前缓存的数据和新数据
    const combinedData = new Int16Array(window.audioDataBuffer.length + int16Data.length);
    combinedData.set(window.audioDataBuffer);
    combinedData.set(int16Data, window.audioDataBuffer.length);
    
    // 处理完整帧
    const frameCount = Math.floor(combinedData.length / FRAME_SIZE);
    console.log(`可编码的完整帧数: ${frameCount}, 缓冲区总大小: ${combinedData.length}`);
    
    for (let i = 0; i < frameCount; i++) {
        const frameData = combinedData.subarray(i * FRAME_SIZE, (i + 1) * FRAME_SIZE);
        
        try {
            console.log(`编码第 ${i+1}/${frameCount} 帧, 帧大小: ${frameData.length}`);
            const encodedData = opusEncoder.encode(frameData);
            if (encodedData && encodedData.length > 0) {
                console.log(`编码成功: ${encodedData.length} 字节`);
                recordedOpusData.push(encodedData);
                window.totalOpusFramesEncoded++;
            } else {
                console.warn(`编码失败: 帧 ${i+1} 返回空数据`);
            }
        } catch (error) {
            console.error(`Opus编码帧 ${i+1} 失败:`, error);
        }
    }
    
    // 保存剩余不足一帧的数据
    const remainingSamples = combinedData.length % FRAME_SIZE;
    if (remainingSamples > 0) {
        window.audioDataBuffer = combinedData.subarray(frameCount * FRAME_SIZE);
        console.log(`保留 ${remainingSamples} 个样本到下一次处理`);
    } else {
        window.audioDataBuffer = new Int16Array(0);
    }
}

function stopRecording() {
    // 检查是否在录音上传模式
    if (isRecordingAndUploading) {
        stopRecordingAndUpload();
        return;
    }
    
    if (!isRecording) return;
    
    // 处理剩余的缓冲数据
    if (window.audioDataBuffer && window.audioDataBuffer.length > 0) {
        console.log(`停止录音，处理剩余的 ${window.audioDataBuffer.length} 个样本`);
        // 如果剩余数据不足一帧，可以通过补零的方式凑成一帧
        if (window.audioDataBuffer.length < FRAME_SIZE) {
            const paddedFrame = new Int16Array(FRAME_SIZE);
            paddedFrame.set(window.audioDataBuffer);
            // 剩余部分填充为0
            for (let i = window.audioDataBuffer.length; i < FRAME_SIZE; i++) {
                paddedFrame[i] = 0;
            }
            try {
                console.log(`编码最后一帧(补零): ${paddedFrame.length} 样本`);
                const encodedData = opusEncoder.encode(paddedFrame);
                if (encodedData) {
                    recordedOpusData.push(encodedData);
                }
            } catch (error) {
                console.error("最后一帧Opus编码失败:", error);
            }
        } else {
            // 如果数据超过一帧，直接处理剩余数据
            const frameCount = Math.floor(window.audioDataBuffer.length / FRAME_SIZE);
            console.log(`处理剩余数据: ${window.audioDataBuffer.length} 样本, 可编码帧数: ${frameCount}`);
            
            for (let i = 0; i < frameCount; i++) {
                const frameData = window.audioDataBuffer.subarray(i * FRAME_SIZE, (i + 1) * FRAME_SIZE);
                
                try {
                    console.log(`编码剩余数据第 ${i+1}/${frameCount} 帧, 帧大小: ${frameData.length}`);
                    const encodedData = opusEncoder.encode(frameData);
                    if (encodedData) {
                        console.log(`编码成功: ${encodedData.length} 字节`);
                        recordedOpusData.push(encodedData);
                    }
                } catch (error) {
                    console.error(`剩余数据Opus编码帧 ${i+1} 失败:`, error);
                }
            }
            
            // 处理剩余不足一帧的数据
            const remainingSamples = window.audioDataBuffer.length % FRAME_SIZE;
            if (remainingSamples > 0) {
                const paddedFrame = new Int16Array(FRAME_SIZE);
                paddedFrame.set(window.audioDataBuffer.subarray(frameCount * FRAME_SIZE));
                // 剩余部分填充为0
                for (let i = remainingSamples; i < FRAME_SIZE; i++) {
                    paddedFrame[i] = 0;
                }
                try {
                    console.log(`编码最后一帧(补零): ${paddedFrame.length} 样本`);
                    const encodedData = opusEncoder.encode(paddedFrame);
                    if (encodedData) {
                        recordedOpusData.push(encodedData);
                    }
                } catch (error) {
                    console.error("最后一帧Opus编码失败:", error);
                }
            }
        }
        window.audioDataBuffer = null;
    }
    
    // 如果使用的是AudioWorklet，调用其特定的停止方法
    if (audioProcessor && typeof audioProcessor.stopRecording === 'function') {
        audioProcessor.stopRecording();
    }
    
    // 停止麦克风
    if (mediaStream) {
        mediaStream.getTracks().forEach(track => track.stop());
    }
    
    // 断开音频处理链
    if (audioProcessor) {
        try {
            audioProcessor.disconnect();
            if (mediaSource) mediaSource.disconnect();
        } catch (error) {
            console.warn("断开音频处理链时出错:", error);
        }
    }
    
    // 更新UI
    isRecording = false;
    statusLabel.textContent = "已停止录音，收集了 " + recordedOpusData.length + " 帧Opus数据";
    startButton.disabled = false;
    stopButton.disabled = true;
    playButton.disabled = recordedOpusData.length === 0;
    
    // 启用下载按钮
    downloadWavButton.disabled = recordedPcmData.length === 0;
    downloadOpusButton.disabled = recordedOpusData.length === 0;
    
    console.log("录制完成:", 
                "PCM帧数:", recordedPcmData.length, 
                "Opus帧数:", recordedOpusData.length);
    
    // 计算实际的音频数据
    let totalPcmSamples = 0;
    for (const chunk of recordedPcmData) {
        totalPcmSamples += chunk.length;
    }
    
    const expectedOpusFrames = Math.ceil(totalPcmSamples / FRAME_SIZE);
    const actualOpusFrames = recordedOpusData.length;
    
    console.log(`音频数据统计:`);
    console.log(`- 总PCM样本数: ${totalPcmSamples}`);
    console.log(`- 处理过的PCM样本数: ${window.totalPcmSamplesProcessed || 0}`);
    console.log(`- 预期OPUS帧数: ${expectedOpusFrames} (${totalPcmSamples} / ${FRAME_SIZE})`);
    console.log(`- 实际OPUS帧数: ${actualOpusFrames}`);
    console.log(`- 编码成功的帧数: ${window.totalOpusFramesEncoded || 0}`);
    console.log(`- 丢失的帧数: ${expectedOpusFrames - actualOpusFrames}`);
    console.log(`- 预期时长: ${(totalPcmSamples / SAMPLE_RATE).toFixed(2)}秒`);
    console.log(`- 实际时长: ${(actualOpusFrames * FRAME_SIZE / SAMPLE_RATE).toFixed(2)}秒`);
    
    // 保存PCM和OPUS音频到本地文件
    console.log("开始保存音频文件...");
    savePCMToFile();
    saveOpusToFile();
    console.log("音频文件保存完成");
}

function playRecording() {
    if (!recordedOpusData.length) {
        statusLabel.textContent = "没有可播放的录音";
        return;
    }
    
    // 将所有Opus数据解码为PCM
    let allDecodedData = [];
    
    for (const opusData of recordedOpusData) {
        try {
            // 解码为Int16数据
            const decodedData = opusDecoder.decode(opusData);
            
            if (decodedData && decodedData.length > 0) {
                // 将Int16数据转换为Float32
                const float32Data = convertInt16ToFloat32(decodedData);
                
                // 添加到总解码数据中
                allDecodedData.push(...float32Data);
            }
        } catch (error) {
            console.error("Opus解码失败:", error);
        }
    }
    
    // 如果没有解码出数据，返回
    if (allDecodedData.length === 0) {
        statusLabel.textContent = "解码失败，无法播放";
        return;
    }
    
    // 创建音频缓冲区
    const audioBuffer = audioContext.createBuffer(CHANNELS, allDecodedData.length, SAMPLE_RATE);
    audioBuffer.copyToChannel(new Float32Array(allDecodedData), 0);
    
    // 创建音频源并播放
    const source = audioContext.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(audioContext.destination);
    source.start();
    
    // 更新UI
    statusLabel.textContent = "正在播放...";
    playButton.disabled = true;
    
    // 播放结束后恢复UI
    source.onended = () => {
        statusLabel.textContent = "播放完毕";
        playButton.disabled = false;
    };
}

// 模拟服务端返回的Opus数据进行解码播放
function playOpusFromServer(opusData) {
    // 这个函数展示如何处理服务端返回的opus数据
    // opusData应该是一个包含opus帧的数组
    
    if (!opusDecoder) {
        initOpus().then(success => {
            if (success) {
                decodeAndPlayOpusData(opusData);
            } else {
                statusLabel.textContent = "Opus解码器初始化失败";
            }
        });
    } else {
        decodeAndPlayOpusData(opusData);
    }
}

function decodeAndPlayOpusData(opusData) {
    let allDecodedData = [];
    
    for (const frame of opusData) {
        try {
            const decodedData = opusDecoder.decode(frame);
            if (decodedData && decodedData.length > 0) {
                const float32Data = convertInt16ToFloat32(decodedData);
                allDecodedData.push(...float32Data);
            }
        } catch (error) {
            console.error("服务端Opus数据解码失败:", error);
        }
    }
    
    if (allDecodedData.length === 0) {
        statusLabel.textContent = "服务端数据解码失败";
        return;
    }
    
    const audioBuffer = audioContext.createBuffer(CHANNELS, allDecodedData.length, SAMPLE_RATE);
    audioBuffer.copyToChannel(new Float32Array(allDecodedData), 0);
    
    const source = audioContext.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(audioContext.destination);
    source.start();
    
    statusLabel.textContent = "正在播放服务端数据...";
    source.onended = () => statusLabel.textContent = "服务端数据播放完毕";
}

// 保存PCM数据为WAV文件
function savePCMToFile() {
    if (!recordedPcmData || recordedPcmData.length === 0) {
        console.log("没有PCM数据可保存");
        return;
    }
    
    // 合并所有PCM数据
    let totalLength = 0;
    for (const chunk of recordedPcmData) {
        totalLength += chunk.length;
    }
    
    const mergedPcmData = new Float32Array(totalLength);
    let offset = 0;
    for (const chunk of recordedPcmData) {
        mergedPcmData.set(chunk, offset);
        offset += chunk.length;
    }
    
    // 计算录音时长
    const duration = (totalLength / SAMPLE_RATE).toFixed(2);
    
    // 创建WAV文件
    const wavBuffer = createWAVFile(mergedPcmData, SAMPLE_RATE, CHANNELS);
    
    // 生成文件名 - 使用本地时间
    const now = new Date();
    const timestamp = now.getFullYear() + '-' + 
                     String(now.getMonth() + 1).padStart(2, '0') + '-' + 
                     String(now.getDate()).padStart(2, '0') + 'T' + 
                     String(now.getHours()).padStart(2, '0') + '-' + 
                     String(now.getMinutes()).padStart(2, '0') + '-' + 
                     String(now.getSeconds()).padStart(2, '0');
    const filename = `录音_PCM_${duration}秒_${timestamp}.wav`;
    
    // 下载文件
    const blob = new Blob([wavBuffer], { type: 'audio/wav' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    
    console.log(`PCM音频已保存为WAV文件: ${filename}, 总样本数: ${totalLength}, 时长: ${duration}秒`);
}

// 创建WAV文件格式
function createWAVFile(pcmData, sampleRate, channels) {
    const length = pcmData.length;
    const buffer = new ArrayBuffer(44 + length * 2);
    const view = new DataView(buffer);
    
    // WAV文件头
    const writeString = (offset, string) => {
        for (let i = 0; i < string.length; i++) {
            view.setUint8(offset + i, string.charCodeAt(i));
        }
    };
    
    writeString(0, 'RIFF');
    view.setUint32(4, 36 + length * 2, true);
    writeString(8, 'WAVE');
    writeString(12, 'fmt ');
    view.setUint32(16, 16, true);
    view.setUint16(20, 1, true);
    view.setUint16(22, channels, true);
    view.setUint32(24, sampleRate, true);
    view.setUint32(28, sampleRate * channels * 2, true);
    view.setUint16(32, channels * 2, true);
    view.setUint16(34, 16, true);
    writeString(36, 'data');
    view.setUint32(40, length * 2, true);
    
    // 转换Float32数据为Int16并写入
    const offset = 44;
    for (let i = 0; i < length; i++) {
        const sample = Math.max(-1, Math.min(1, pcmData[i]));
        const int16Sample = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;
        view.setInt16(offset + i * 2, int16Sample, true);
    }
    
    return buffer;
}

// 保存OPUS数据为文件
function saveOpusToFile() {
    if (!recordedOpusData || recordedOpusData.length === 0) {
        console.log("没有OPUS数据可保存");
        return;
    }
    
    try {
        console.log(`开始保存OPUS文件，OPUS帧数: ${recordedOpusData.length}`);
        
        // 直接使用OPUS格式保存
        console.log("使用OPUS格式保存音频数据");
        saveOpusAsRawBinary();
    } catch (error) {
        console.error("保存OPUS文件时出错:", error);
        statusLabel.textContent = "保存OPUS文件失败: " + error.message;
    }
}

// 保存为原始二进制格式
function saveOpusAsRawBinary() {
    // 计算总字节数
    let totalBytes = 0;
    for (const frame of recordedOpusData) {
        totalBytes += frame.length + 4; // 每帧数据 + 4字节长度前缀
    }
    
    // 添加文件头信息（可选）
    const headerSize = 19 + 6; // OpusHead(19字节) + 自定义扩展(6字节)
    const totalSize = headerSize + totalBytes;
    
    // 创建缓冲区存储文件头和所有OPUS帧
    const buffer = new ArrayBuffer(totalSize);
    const view = new DataView(buffer);
    const uint8View = new Uint8Array(buffer);
    
    // 写入文件头信息
    let offset = 0;
    
    // 使用标准的OPUS文件头格式
    // "OpusHead" 标识 (8字节)
    const opusHead = [0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]; // "OpusHead"
    uint8View.set(opusHead, offset);
    offset += 8;
    
    // 版本号 (1字节)
    uint8View[offset++] = 1;
    
    // 通道数 (1字节)
    uint8View[offset++] = CHANNELS;
    
    // 预跳过样本数 (16位，小端序) - 设置为80ms的样本数
    const preSkip = Math.floor(SAMPLE_RATE * 0.08); // 80ms
    view.setUint16(offset, preSkip, true);
    offset += 2;
    
    // 采样率 (32位，小端序)
    view.setUint32(offset, SAMPLE_RATE, true);
    offset += 4;
    
    // 输出增益 (16位，小端序)
    view.setUint16(offset, 0, true);
    offset += 2;
    
    // 通道映射 (1字节)
    uint8View[offset++] = 0;
    
    // 添加自定义扩展头
    // 帧大小 (2字节，小端序)
    view.setUint16(offset, FRAME_SIZE, true);
    offset += 2;
    
    // 总帧数 (4字节，小端序)
    view.setUint32(offset, recordedOpusData.length, true);
    offset += 4;
    
    // 写入所有OPUS帧
    for (const frame of recordedOpusData) {
        // 写入帧长度（4字节，小端序）
        view.setUint32(offset, frame.length, true);
        offset += 4;
        
        // 写入帧数据
        uint8View.set(frame, offset);
        offset += frame.length;
    }
    
    // 计算录音时长
    const duration = ((recordedOpusData.length * FRAME_SIZE) / SAMPLE_RATE).toFixed(2);
    
    // 生成文件名 - 使用本地时间
    const now = new Date();
    const timestamp = now.getFullYear() + '-' + 
                     String(now.getMonth() + 1).padStart(2, '0') + '-' + 
                     String(now.getDate()).padStart(2, '0') + 'T' + 
                     String(now.getHours()).padStart(2, '0') + '-' + 
                     String(now.getMinutes()).padStart(2, '0') + '-' + 
                     String(now.getSeconds()).padStart(2, '0');
    const filename = `录音_OPUS_${duration}秒_${timestamp}.opus`;
    
    // 下载OPUS文件
    const blob = new Blob([buffer], { type: 'application/octet-stream' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    
    console.log(`OPUS音频已保存: ${filename}, 总帧数: ${recordedOpusData.length}，总字节数: ${totalSize}, 时长: ${duration}秒`);
    console.log(`文件头信息: 采样率=${SAMPLE_RATE}Hz, 通道=${CHANNELS}, 帧大小=${FRAME_SIZE}, 总帧数=${recordedOpusData.length}`);
}

// 创建OGG容器格式
function createOGGFile(opusFrames, sampleRate, channels) {
    console.log(`创建OGG文件: ${opusFrames.length} 帧, 采样率: ${sampleRate}, 通道: ${channels}`);
    
    const pages = [];
    let pageNumber = 0;
    let granulePosition = 0;
    let packetNumber = 0;
    
    try {
        // 创建识别头页面
        console.log("创建OpusHead页面...");
        const identificationHeader = createOpusHead(sampleRate, channels);
        console.log(`OpusHead结果: 类型=${typeof identificationHeader}, 长度=${identificationHeader ? identificationHeader.length : 'undefined'}`);
        pages.push(createOGGPage([identificationHeader], pageNumber++, 0, 0, true, false));
        
        // 创建注释头页面
        console.log("创建OpusTags页面...");
        const commentHeader = createOpusTags();
        console.log(`OpusTags结果: 类型=${typeof commentHeader}, 长度=${commentHeader ? commentHeader.length : 'undefined'}`);
        pages.push(createOGGPage([commentHeader], pageNumber++, 0, 0, false, false));
        
        // 创建数据页面
        console.log(`创建 ${opusFrames.length} 个数据页面...`);
        for (let i = 0; i < opusFrames.length; i++) {
            const frame = opusFrames[i];
            const isLastPage = (i === opusFrames.length - 1);
            console.log(`创建数据页面 ${i+1}/${opusFrames.length}, 帧大小: ${frame.length}, 是否最后一页: ${isLastPage}, 当前粒度位置: ${granulePosition}`);
            pages.push(createOGGPage([frame], pageNumber++, granulePosition, packetNumber++, false, isLastPage));
            granulePosition += FRAME_SIZE; // 每帧960个采样点
        }
        
        // 合并所有页面
        let totalSize = 0;
        for (const page of pages) {
            totalSize += page.length;
        }
        
        console.log(`合并页面，总大小: ${totalSize} 字节`);
        
        const buffer = new ArrayBuffer(totalSize);
        const uint8View = new Uint8Array(buffer);
        let offset = 0;
        
        for (const page of pages) {
            uint8View.set(page, offset);
            offset += page.length;
        }
        
        console.log("OGG文件创建完成");
        return buffer;
    } catch (error) {
        console.error("创建OGG文件时出错:", error);
        throw error;
    }
}

// 创建OpusHead包
function createOpusHead(sampleRate, channels) {
    const buffer = new ArrayBuffer(19);
    const view = new DataView(buffer);
    const uint8View = new Uint8Array(buffer);
    
    // "OpusHead" 标识
    const opusHead = [0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]; // "OpusHead"
    uint8View.set(opusHead, 0);
    
    // 版本号 (1)
    uint8View[8] = 1;
    
    // 通道数
    uint8View[9] = channels;
    
    // 预跳过样本数 (16位，小端序)
    view.setUint16(10, 0, true);
    
    // 采样率 (32位，小端序)
    view.setUint32(12, sampleRate, true);
    
    // 输出增益 (16位，小端序)
    view.setUint16(16, 0, true);
    
    // 通道映射
    uint8View[18] = 0;
    
    const result = new Uint8Array(buffer);
    console.log(`创建OpusHead: 大小=${result.length}, 采样率=${sampleRate}, 通道=${channels}, 类型=${typeof result}, 是否为Uint8Array=${result instanceof Uint8Array}`);
    return result;
}

// 创建OpusTags包
function createOpusTags() {
    const buffer = new ArrayBuffer(16);
    const view = new DataView(buffer);
    const uint8View = new Uint8Array(buffer);
    
    // "OpusTags" 标识
    const opusTags = [0x4F, 0x70, 0x75, 0x73, 0x54, 0x61, 0x67, 0x73]; // "OpusTags"
    uint8View.set(opusTags, 0);
    
    // 供应商字符串长度 (32位，小端序)
    view.setUint32(8, 0, true);
    
    // 用户注释列表长度 (32位，小端序)
    view.setUint32(12, 0, true);
    
    const result = new Uint8Array(buffer);
    console.log(`创建OpusTags: 大小=${result.length}`);
    return result;
}

// 创建OGG页面
function createOGGPage(packets, pageNumber, granulePosition, packetNumber, isFirstPage, isLastPage) {
    console.log(`createOGGPage调用: packets=${packets.length}, pageNumber=${pageNumber}, granulePosition=${granulePosition}`);
    
    // 计算页面大小
    const packetSizes = [];
    let totalPacketSize = 0;
    
    for (let i = 0; i < packets.length; i++) {
        const packet = packets[i];
        const packetLength = packet ? packet.length : 0;
        console.log(`数据包 ${i}: 长度=${packetLength}, 类型=${typeof packet}, 是否为数组=${Array.isArray(packet)}`);
        packetSizes.push(packetLength);
        totalPacketSize += packetLength;
    }
    
    // 页面大小 = 27字节头 + 段表大小 + 数据包总大小
    const pageSize = 27 + packets.length + totalPacketSize;
    
    console.log(`创建OGG页面: 大小=${pageSize}, 段数=${packets.length}, 数据大小=${totalPacketSize}, 粒度位置=${granulePosition}`);
    console.log(`计算详情: 27 + ${packets.length} + ${totalPacketSize} = ${pageSize}`);
    
    // 创建页面
    const page = new Uint8Array(pageSize);
    const view = new DataView(page.buffer);
    
    console.log(`页面缓冲区大小: ${page.buffer.byteLength}, 需要大小: ${pageSize}`);
    
    if (page.buffer.byteLength < pageSize) {
        throw new Error(`缓冲区大小不足: 需要${pageSize}, 实际${page.buffer.byteLength}`);
    }
    
    // OGG页面头
    // 捕获模式 "OggS"
    page[0] = 0x4F; // 'O'
    page[1] = 0x67; // 'g'
    page[2] = 0x67; // 'g'
    page[3] = 0x53; // 'S'
    
    // 版本
    page[4] = 0;
    
    // 页面类型标志
    let pageType = 0;
    if (isFirstPage) pageType |= 0x02;
    if (isLastPage) pageType |= 0x04;
    page[5] = pageType;
    
    // 粒度位置 (64位，小端序) - 使用更安全的方法
    let granuleLow, granuleHigh;
    
    if (granulePosition <= 0xFFFFFFFF) {
        // 如果小于等于32位最大值，直接使用
        granuleLow = granulePosition;
        granuleHigh = 0;
    } else {
        // 如果大于32位，需要分割
        granuleLow = granulePosition & 0xFFFFFFFF;
        granuleHigh = Math.floor(granulePosition / 0x100000000);
    }
    
    console.log(`写入粒度位置: 原始值=${granulePosition}, 低32位=${granuleLow}, 高32位=${granuleHigh}`);
    
    try {
        view.setUint32(6, granuleLow, true);
        view.setUint32(10, granuleHigh, true);
    } catch (error) {
        console.error(`DataView写入失败: 偏移6=${granuleLow}, 偏移10=${granuleHigh}, 错误:`, error);
        throw error;
    }
    
    // 比特流序列号 (32位，小端序)
    view.setUint32(14, 1, true);
    
    // 页面序列号 (32位，小端序)
    view.setUint32(18, pageNumber, true);
    
    // CRC校验和 (32位，小端序) - 先设为0，后面计算
    view.setUint32(22, 0, true);
    
    // 页面段数
    page[26] = packets.length;
    
    // 段表 - 简化处理，因为我们每个页面只有一个数据包
    let offset = 27;
    for (let i = 0; i < packets.length; i++) {
        const packetSize = packetSizes[i];
        page[offset++] = packetSize;
    }
    
    // 添加数据包
    for (const packet of packets) {
        page.set(packet, offset);
        offset += packet.length;
    }
    
    // 计算CRC校验和
    const crc = calculateOGGCRC(page);
    view.setUint32(22, crc, true);
    
    return page;
}

// 计算OGG CRC校验和
function calculateOGGCRC(data) {
    let crc = 0;
    for (let i = 0; i < data.length; i++) {
        if (i >= 22 && i < 26) continue; // 跳过CRC字段
        crc = ((crc << 8) ^ crcTable[((crc >>> 24) ^ data[i]) & 0xFF]) >>> 0;
    }
    return crc;
}

// CRC表 (预计算)
const crcTable = new Uint32Array(256);
for (let i = 0; i < 256; i++) {
    let crc = i << 24;
    for (let j = 0; j < 8; j++) {
        if (crc & 0x80000000) {
            crc = ((crc << 1) ^ 0x04C11DB7) >>> 0;
        } else {
            crc = (crc << 1) >>> 0;
        }
    }
    crcTable[i] = crc;
}

// 从保存的OPUS文件中加载数据（可选功能）
function loadOpusFromFile(fileInput) {
    const file = fileInput.files[0];
    if (!file) return;
    
    const reader = new FileReader();
    reader.onload = function(e) {
        const buffer = e.target.result;
        const uint8View = new Uint8Array(buffer);
        
        try {
            // 首先尝试解析新的文件格式（带文件头）
            const loadedOpusData = parseOpusFileWithHeader(uint8View);
            if (loadedOpusData && loadedOpusData.length > 0) {
                console.log(`从新格式文件加载了 ${loadedOpusData.length} 帧OPUS数据`);
                playOpusFromServer(loadedOpusData);
                return;
            }
        } catch (error) {
            console.log("新格式解析失败，尝试其他格式:", error);
        }
        
        try {
            // 尝试解析OGG格式
            const loadedOpusData = parseOGGFile(uint8View);
            console.log(`从OGG文件加载了 ${loadedOpusData.length} 帧OPUS数据`);
            playOpusFromServer(loadedOpusData);
        } catch (error) {
            console.error("解析OGG文件失败:", error);
            // 尝试解析旧的二进制格式
            try {
                const view = new DataView(buffer);
                const oldFormatData = [];
                let offset = 0;
                
                while (offset < buffer.byteLength) {
                    const frameLength = view.getUint32(offset, true);
                    offset += 4;
                    
                    if (offset + frameLength > buffer.byteLength) break;
                    
                    const frameData = uint8View.slice(offset, offset + frameLength);
                    oldFormatData.push(frameData);
                    offset += frameLength;
                }
                
                if (oldFormatData.length > 0) {
                    console.log(`从旧格式文件加载了 ${oldFormatData.length} 帧OPUS数据`);
                    playOpusFromServer(oldFormatData);
                }
            } catch (oldError) {
                console.error("解析旧格式文件也失败:", oldError);
            }
        }
    };
    
    reader.readAsArrayBuffer(file);
}

// 解析带文件头的新OPUS格式
function parseOpusFileWithHeader(data) {
    const view = new DataView(data.buffer);
    
    // 检查 "OpusHead" 标识
    const opusHead = String.fromCharCode(...data.slice(0, 8));
    if (opusHead !== "OpusHead") {
        throw new Error("不是有效的OPUS文件格式");
    }
    
    let offset = 8;
    
    // 读取版本号
    const version = data[offset++];
    console.log(`OPUS文件版本: ${version}`);
    
    // 读取通道数
    const channels = data[offset++];
    console.log(`通道数: ${channels}`);
    
    // 读取预跳过样本数
    const preSkip = view.getUint16(offset, true);
    offset += 2;
    console.log(`预跳过样本数: ${preSkip}`);
    
    // 读取采样率
    const sampleRate = view.getUint32(offset, true);
    offset += 4;
    console.log(`采样率: ${sampleRate}Hz`);
    
    // 读取输出增益
    const outputGain = view.getUint16(offset, true);
    offset += 2;
    console.log(`输出增益: ${outputGain}`);
    
    // 读取通道映射
    const channelMapping = data[offset++];
    console.log(`通道映射: ${channelMapping}`);
    
    // 读取自定义扩展信息
    const frameSize = view.getUint16(offset, true);
    offset += 2;
    console.log(`帧大小: ${frameSize}`);
    
    const totalFrames = view.getUint32(offset, true);
    offset += 4;
    console.log(`总帧数: ${totalFrames}`);
    
    // 读取所有OPUS帧
    const opusFrames = [];
    for (let i = 0; i < totalFrames; i++) {
        if (offset + 4 > data.length) break;
        
        const frameLength = view.getUint32(offset, true);
        offset += 4;
        
        if (offset + frameLength > data.length) break;
        
        const frameData = data.slice(offset, offset + frameLength);
        opusFrames.push(frameData);
        offset += frameLength;
    }
    
    console.log(`成功解析 ${opusFrames.length} 帧OPUS数据`);
    return opusFrames;
}

// 解析OGG文件
function parseOGGFile(data) {
    const opusFrames = [];
    let offset = 0;
    
    while (offset < data.length) {
        // 检查OGG页面头
        if (data[offset] !== 0x4F || data[offset + 1] !== 0x67 || 
            data[offset + 2] !== 0x67 || data[offset + 3] !== 0x53) {
            throw new Error("无效的OGG页面头");
        }
        
        // 读取页面段数
        const segmentCount = data[offset + 26];
        
        // 计算段表大小
        const segmentTableSize = segmentCount;
        const pageHeaderSize = 27 + segmentTableSize;
        
        // 读取段表
        const segments = [];
        for (let i = 0; i < segmentCount; i++) {
            segments.push(data[offset + 27 + i]);
        }
        
        // 处理每个段
        let packetOffset = offset + pageHeaderSize;
        for (let i = 0; i < segments.length; i++) {
            const segmentSize = segments[i];
            if (segmentSize > 0) {
                const packet = data.slice(packetOffset, packetOffset + segmentSize);
                
                // 检查是否是OpusHead或OpusTags（跳过）
                if (packet.length >= 8) {
                    const header = String.fromCharCode(...packet.slice(0, 8));
                    if (header !== "OpusHead" && header !== "OpusTags") {
                        // 这是OPUS音频数据
                        opusFrames.push(packet);
                    }
                }
                
                packetOffset += segmentSize;
            }
        }
        
        // 移动到下一个页面
        offset = packetOffset;
    }
    
    return opusFrames;
}

// 创建正确的OGG格式
function createCorrectOGGFile(opusFrames, sampleRate, channels) {
            console.log(`创建简化OGG文件: ${opusFrames.length} 帧, 采样率: ${sampleRate}, 通道: ${channels}`);
        console.log(`预期总时长: ${(opusFrames.length * FRAME_SIZE / sampleRate).toFixed(2)}秒`);
        console.log(`预期总采样点: ${opusFrames.length * FRAME_SIZE}`);
    
    const pages = [];
    let pageNumber = 0;
    let granulePosition = 0;
    
    try {
        // 创建OpusHead页面
        console.log("创建OpusHead页面...");
        const opusHead = createOpusHead(sampleRate, channels);
        pages.push(createCorrectOGGPage([opusHead], pageNumber++, 0, true, false));
        
        // 创建OpusTags页面
        console.log("创建OpusTags页面...");
        const opusTags = createOpusTags();
        pages.push(createCorrectOGGPage([opusTags], pageNumber++, 0, false, false));
        
        // 创建数据页面
        console.log(`创建 ${opusFrames.length} 个数据页面...`);
        for (let i = 0; i < opusFrames.length; i++) {
            const frame = opusFrames[i];
            const isLastPage = (i === opusFrames.length - 1);
            
            // 计算正确的粒度位置：累积的采样点数
            // 每个OPUS帧对应FRAME_SIZE个采样点，但我们需要累积计算
            const currentGranulePosition = (i + 1) * FRAME_SIZE;
            
            console.log(`创建数据页面 ${i+1}/${opusFrames.length}, 帧大小: ${frame.length}, 粒度位置: ${currentGranulePosition}, 是否最后一页: ${isLastPage}`);
            pages.push(createCorrectOGGPage([frame], pageNumber++, currentGranulePosition, false, isLastPage));
            
            // 验证时长计算
            const expectedDuration = (currentGranulePosition / sampleRate).toFixed(2);
            console.log(`预期时长: ${expectedDuration}秒 (${currentGranulePosition} 采样点 / ${sampleRate}Hz)`);
        }
        
        // 合并所有页面
        let totalSize = 0;
        for (const page of pages) {
            totalSize += page.length;
        }
        
        console.log(`合并页面，总大小: ${totalSize} 字节`);
        
        const buffer = new ArrayBuffer(totalSize);
        const uint8View = new Uint8Array(buffer);
        let offset = 0;
        
        for (const page of pages) {
            uint8View.set(page, offset);
            offset += page.length;
        }
        
        console.log("简化OGG文件创建完成");
        return buffer;
    } catch (error) {
        console.error("创建简化OGG文件时出错:", error);
        throw error;
    }
}

// 创建正确的OGG页面
function createCorrectOGGPage(packets, pageNumber, granulePosition, isFirstPage, isLastPage) {
    const packetSizes = [];
    let totalPacketSize = 0;
    
    for (const packet of packets) {
        packetSizes.push(packet.length);
        totalPacketSize += packet.length;
    }
    
    // 页面大小 = 27字节头 + 段表大小 + 数据包总大小
    const pageSize = 27 + packets.length + totalPacketSize;
    
    console.log(`创建简化OGG页面: 大小=${pageSize}, 段数=${packets.length}, 数据大小=${totalPacketSize}, 粒度位置=${granulePosition}`);
    
    // 创建页面
    const page = new Uint8Array(pageSize);
    const view = new DataView(page.buffer);
    
    // OGG页面头
    page[0] = 0x4F; // 'O'
    page[1] = 0x67; // 'g'
    page[2] = 0x67; // 'g'
    page[3] = 0x53; // 'S'
    page[4] = 0; // 版本
    
    // 页面类型标志
    let pageType = 0;
    if (isFirstPage) pageType |= 0x02;
    if (isLastPage) pageType |= 0x04;
    page[5] = pageType;
    
    // 粒度位置 (64位，小端序)
    // 对于OPUS，粒度位置表示的是音频的采样点数
    const granuleLow = granulePosition & 0xFFFFFFFF;
    const granuleHigh = Math.floor(granulePosition / 0x100000000);
    
    console.log(`设置粒度位置: ${granulePosition} -> 低32位: ${granuleLow}, 高32位: ${granuleHigh}`);
    
    view.setUint32(6, granuleLow, true);
    view.setUint32(10, granuleHigh, true);
    
    // 比特流序列号 (32位，小端序)
    view.setUint32(14, 1, true);
    
    // 页面序列号 (32位，小端序)
    view.setUint32(18, pageNumber, true);
    
    // CRC校验和 (32位，小端序) - 先设为0
    view.setUint32(22, 0, true);
    
    // 页面段数
    page[26] = packets.length;
    
    // 段表
    let offset = 27;
    for (let i = 0; i < packets.length; i++) {
        page[offset++] = packetSizes[i];
    }
    
    // 添加数据包
    for (const packet of packets) {
        page.set(packet, offset);
        offset += packet.length;
    }
    
    // 计算CRC校验和
    const crc = calculateOGGCRC(page);
    view.setUint32(22, crc, true);
    
    return page;
}

// 验证OGG文件格式
function validateOGGFile(buffer) {
    const uint8View = new Uint8Array(buffer);
    const view = new DataView(buffer);
    
    console.log("开始验证OGG文件格式...");
    
    // 检查文件大小
    if (buffer.byteLength < 27) {
        console.error("文件太小，不是有效的OGG文件");
        return false;
    }
    
    // 检查第一个页面的OGG头
    if (uint8View[0] !== 0x4F || uint8View[1] !== 0x67 || 
        uint8View[2] !== 0x67 || uint8View[3] !== 0x53) {
        console.error("无效的OGG页面头");
        return false;
    }
    
    // 检查页面类型标志
    const pageType = uint8View[5];
    console.log(`第一个页面类型: ${pageType} (应该包含开始标志)`);
    
    // 检查页面段数
    const segmentCount = uint8View[26];
    console.log(`第一个页面段数: ${segmentCount}`);
    
    // 检查是否有OpusHead
    let offset = 27 + segmentCount; // 跳过段表
    if (offset + 8 <= buffer.byteLength) {
        const header = String.fromCharCode(...uint8View.slice(offset, offset + 8));
        console.log(`第一个数据包标识: ${header}`);
        if (header !== "OpusHead") {
            console.error("缺少OpusHead标识");
            return false;
        }
    }
    
    console.log("OGG文件格式基本验证通过");
    return true;
}

// 处理导入OPUS文件
async function handleImportOpusFile(event) {
    const file = event.target.files[0];
    if (!file) {
        importStatus.textContent = "未选择文件";
        return;
    }
    
    console.log(`导入OPUS文件: ${file.name}, 大小: ${file.size} 字节`);
    importStatus.textContent = "正在解析文件...";
    
    const reader = new FileReader();
    reader.onload = function(e) {
        try {
            const buffer = e.target.result;
            const uint8View = new Uint8Array(buffer);
            
            let loadedOpusData = null;
            let fileType = "";
            
            // 尝试解析不同的格式
            try {
                // 首先尝试解析新的文件格式（带文件头）
                loadedOpusData = parseOpusFileWithHeader(uint8View);
                if (loadedOpusData && loadedOpusData.length > 0) {
                    fileType = "自定义OPUS格式";
                    console.log(`从自定义OPUS格式文件加载了 ${loadedOpusData.length} 帧OPUS数据`);
                }
            } catch (error) {
                console.log("自定义格式解析失败，尝试其他格式:", error);
            }
            
            if (!loadedOpusData) {
                try {
                    // 尝试解析OGG格式
                    loadedOpusData = parseOGGFile(uint8View);
                    fileType = "OGG/OPUS格式";
                    console.log(`从OGG文件加载了 ${loadedOpusData.length} 帧OPUS数据`);
                } catch (error) {
                    console.error("解析OGG文件失败:", error);
                }
            }
            
            if (!loadedOpusData) {
                try {
                    // 尝试解析旧的二进制格式
                    const view = new DataView(buffer);
                    const oldFormatData = [];
                    let offset = 0;
                    
                    while (offset < buffer.byteLength) {
                        const frameLength = view.getUint32(offset, true);
                        offset += 4;
                        
                        if (offset + frameLength > buffer.byteLength) break;
                        
                        const frameData = uint8View.slice(offset, offset + frameLength);
                        oldFormatData.push(frameData);
                        offset += frameLength;
                    }
                    
                    if (oldFormatData.length > 0) {
                        loadedOpusData = oldFormatData;
                        fileType = "原始二进制格式";
                        console.log(`从原始二进制格式文件加载了 ${loadedOpusData.length} 帧OPUS数据`);
                    }
                } catch (oldError) {
                    console.error("解析原始二进制格式文件也失败:", oldError);
                }
            }
            
            if (loadedOpusData && loadedOpusData.length > 0) {
                // 替换当前录制的OPUS数据
                recordedOpusData = loadedOpusData;
                
                // 确保OPUS解码器已初始化
                if (!opusDecoder) {
                    console.log("OPUS解码器未初始化，正在初始化...");
                    try {
                        const success = initOpus();
                        if (!success) {
                            throw new Error("OPUS初始化返回false");
                        }
                        console.log("OPUS解码器初始化成功");
                    } catch (error) {
                        console.error("OPUS解码器初始化失败:", error);
                        importStatus.textContent = "OPUS解码器初始化失败，无法播放";
                        importStatus.style.color = "#db4437";
                        return;
                    }
                }
                
                // 计算时长
                const duration = ((loadedOpusData.length * FRAME_SIZE) / SAMPLE_RATE).toFixed(2);
                
                // 更新UI
                statusLabel.textContent = `已导入OPUS文件: ${file.name} (${duration}秒, ${loadedOpusData.length}帧)`;
                playButton.disabled = false;
                importStatus.textContent = `导入成功: ${fileType}, ${duration}秒, ${loadedOpusData.length}帧`;
                importStatus.style.color = "#0f9d58";
                
                console.log(`OPUS文件导入成功: ${file.name}, 格式: ${fileType}, 时长: ${duration}秒, 帧数: ${loadedOpusData.length}`);
            } else {
                importStatus.textContent = "文件格式不支持或解析失败";
                importStatus.style.color = "#db4437";
                console.error("无法解析OPUS文件格式");
            }
        } catch (error) {
            importStatus.textContent = "文件读取失败: " + error.message;
            importStatus.style.color = "#db4437";
            console.error("导入OPUS文件失败:", error);
        }
    };
    
    reader.onerror = function() {
        importStatus.textContent = "文件读取失败";
        importStatus.style.color = "#db4437";
        console.error("文件读取失败");
    };
    
    reader.readAsArrayBuffer(file);
}

// 录音并上传函数
async function startRecordingAndUpload() {
    try {
        if (isRecordingAndUploading) {
            console.log("已经在录音上传中");
            return;
        }

        // 初始化Opus编码器
        statusLabel.textContent = "正在初始化Opus编码器...";
        const opusInitSuccess = await initOpus();
        if (!opusInitSuccess) {
            console.error("Opus编码器初始化失败");
            statusLabel.textContent = "错误：Opus编码器初始化失败";
            return;
        }
        
        console.log("Opus编码器初始化成功");

        // 连接WebSocket
        statusLabel.textContent = "正在连接WebSocket...";
        await connectWebSocket();

        // 开始录音
        isRecordingAndUploading = true;
        recordedOpusData = []; // 清空之前的数据
        recordedPcmData = [];
        
        // 重置计数器
        window.totalPcmSamplesProcessed = 0;
        window.totalOpusFramesEncoded = 0;
        window.audioDataBuffer = new Int16Array(0);

        // 更新UI状态
        startAndUploadButton.disabled = true;
        startAndUploadButton.textContent = "录音上传中...";
        stopButton.disabled = false;
        playButton.disabled = true;
        downloadWavButton.disabled = true;
        downloadOpusButton.disabled = true;

        statusLabel.textContent = "正在录音并上传...";

        // 获取麦克风权限并开始录音
        await continueStartRecordingForUpload();

    } catch (error) {
        console.error("开始录音上传失败:", error);
        statusLabel.textContent = `录音上传失败: ${error.message}`;
        isRecordingAndUploading = false;
        startAndUploadButton.disabled = false;
        startAndUploadButton.textContent = "录音并上传";
    }
}

// 继续录音上传流程
async function continueStartRecordingForUpload() {
    try {
        // 获取麦克风权限
        mediaStream = await navigator.mediaDevices.getUserMedia({
            audio: {
                echoCancellation: true,
                noiseSuppression: true,
                autoGainControl: true,
                sampleRate: SAMPLE_RATE,
                channelCount: CHANNELS
            }
        });

        console.log("麦克风权限获取成功");

        // 创建音频源
        mediaSource = audioContext.createMediaStreamSource(mediaStream);

        // 创建音频处理器
        await createAudioProcessorForUpload();

        // 连接音频处理链
        mediaSource.connect(audioProcessor);
        audioProcessor.connect(audioContext.destination);

        console.log("录音上传开始");

    } catch (error) {
        console.error("录音上传初始化失败:", error);
        statusLabel.textContent = `录音上传初始化失败: ${error.message}`;
        isRecordingAndUploading = false;
        startAndUploadButton.disabled = false;
        startAndUploadButton.textContent = "录音并上传";
        
        // 关闭WebSocket连接
        if (wsClient && wsClient.readyState === WebSocket.OPEN) {
            wsClient.close();
        }
    }
}

// 创建音频处理器（用于上传）
async function createAudioProcessorForUpload() {
    try {
        audioProcessor = audioContext.createScriptProcessor(BUFFER_SIZE, 1, 1);
        
        audioProcessor.onaudioprocess = function(e) {
            if (isRecordingAndUploading) {
                processAudioDataForUpload(e);
            }
        };

        console.log("音频处理器创建成功（上传模式）");
    } catch (error) {
        console.error("创建音频处理器失败:", error);
        throw error;
    }
}

// 处理音频数据（上传模式）
function processAudioDataForUpload(e) {
    // 获取输入缓冲区
    const inputBuffer = e.inputBuffer;
    
    // 获取第一个通道的Float32数据
    const inputData = inputBuffer.getChannelData(0);
    
    // 添加调试信息
    const nonZeroCount = Array.from(inputData).filter(x => Math.abs(x) > 0.001).length;
    console.log(`接收到音频数据: ${inputData.length} 个样本, 非零样本数: ${nonZeroCount}`);
    
    // 如果全是0，可能是麦克风没有正确获取声音
    if (nonZeroCount < 5) {
        console.warn("警告: 检测到大量静音样本，请检查麦克风是否正常工作");
    }
    
    // 存储PCM数据用于调试
    recordedPcmData.push(new Float32Array(inputData));
    
    // 更新PCM样本计数器
    window.totalPcmSamplesProcessed += inputData.length;
    
    // 转换为Int16数据供Opus编码
    const int16Data = convertFloat32ToInt16(inputData);
    
    // 如果收集到的数据不是FRAME_SIZE的整数倍，需要进行处理
    if (!window.audioDataBuffer) {
        window.audioDataBuffer = new Int16Array(0);
    }
    
    // 合并之前缓存的数据和新数据
    const combinedData = new Int16Array(window.audioDataBuffer.length + int16Data.length);
    combinedData.set(window.audioDataBuffer);
    combinedData.set(int16Data, window.audioDataBuffer.length);
    
    // 处理完整帧
    const frameCount = Math.floor(combinedData.length / FRAME_SIZE);
    console.log(`可编码的完整帧数: ${frameCount}, 缓冲区总大小: ${combinedData.length}`);
    
    for (let i = 0; i < frameCount; i++) {
        const frameData = combinedData.subarray(i * FRAME_SIZE, (i + 1) * FRAME_SIZE);
        
        try {
            console.log(`编码第 ${i+1}/${frameCount} 帧, 帧大小: ${frameData.length}`);
            const encodedData = opusEncoder.encode(frameData);
            if (encodedData && encodedData.length > 0) {
                console.log(`编码成功: ${encodedData.length} 字节，准备上传`);
                recordedOpusData.push(encodedData);
                window.totalOpusFramesEncoded++;
                
                // 立即通过WebSocket发送
                if (wsClient && wsClient.readyState === WebSocket.OPEN) {
                    try {
                        wsClient.send(encodedData);
                        console.log(`已发送帧 ${window.totalOpusFramesEncoded}: ${encodedData.length} 字节`);
                    } catch (sendError) {
                        console.error(`发送帧 ${window.totalOpusFramesEncoded} 失败:`, sendError);
                    }
                } else {
                    console.warn("WebSocket连接不可用，无法发送数据");
                }
            } else {
                console.warn(`编码失败: 帧 ${i+1} 返回空数据`);
            }
        } catch (error) {
            console.error(`Opus编码帧 ${i+1} 失败:`, error);
        }
    }
    
    // 保存剩余不足一帧的数据
    const remainingSamples = combinedData.length % FRAME_SIZE;
    if (remainingSamples > 0) {
        window.audioDataBuffer = combinedData.subarray(frameCount * FRAME_SIZE);
        console.log(`保留 ${remainingSamples} 个样本到下一次处理`);
    } else {
        window.audioDataBuffer = new Int16Array(0);
    }
}

// 停止录音上传
function stopRecordingAndUpload() {
    if (!isRecordingAndUploading) return;
    
    console.log("停止录音上传");
    isRecordingAndUploading = false;
    
    // 处理剩余的缓冲数据
    if (window.audioDataBuffer && window.audioDataBuffer.length > 0) {
        console.log(`停止录音上传，处理剩余的 ${window.audioDataBuffer.length} 个样本`);
        // 如果剩余数据不足一帧，可以通过补零的方式凑成一帧
        if (window.audioDataBuffer.length < FRAME_SIZE) {
            const paddedFrame = new Int16Array(FRAME_SIZE);
            paddedFrame.set(window.audioDataBuffer);
            // 剩余部分填充为0
            for (let i = window.audioDataBuffer.length; i < FRAME_SIZE; i++) {
                paddedFrame[i] = 0;
            }
            try {
                console.log(`编码最后一帧(补零): ${paddedFrame.length} 样本`);
                const encodedData = opusEncoder.encode(paddedFrame);
                if (encodedData) {
                    recordedOpusData.push(encodedData);
                    // 发送最后一帧
                    if (wsClient && wsClient.readyState === WebSocket.OPEN) {
                        wsClient.send(encodedData);
                        console.log(`已发送最后一帧: ${encodedData.length} 字节`);
                    }
                }
            } catch (error) {
                console.error("最后一帧Opus编码失败:", error);
            }
        } else {
            // 如果数据超过一帧，直接处理剩余数据
            const frameCount = Math.floor(window.audioDataBuffer.length / FRAME_SIZE);
            console.log(`处理剩余数据: ${window.audioDataBuffer.length} 样本, 可编码帧数: ${frameCount}`);
            
            for (let i = 0; i < frameCount; i++) {
                const frameData = window.audioDataBuffer.subarray(i * FRAME_SIZE, (i + 1) * FRAME_SIZE);
                
                try {
                    const encodedData = opusEncoder.encode(frameData);
                    if (encodedData) {
                        recordedOpusData.push(encodedData);
                        // 发送剩余帧
                        if (wsClient && wsClient.readyState === WebSocket.OPEN) {
                            wsClient.send(encodedData);
                            console.log(`已发送剩余帧 ${i+1}: ${encodedData.length} 字节`);
                        }
                    }
                } catch (error) {
                    console.error(`剩余帧 ${i+1} Opus编码失败:`, error);
                }
            }
        }
    }
    
    // 停止音频处理
    if (audioProcessor) {
        audioProcessor.disconnect();
        audioProcessor = null;
    }
    
    if (mediaSource) {
        mediaSource.disconnect();
        mediaSource = null;
    }
    
    if (mediaStream) {
        mediaStream.getTracks().forEach(track => track.stop());
        mediaStream = null;
    }
    
    // 关闭WebSocket连接
    if (wsClient && wsClient.readyState === WebSocket.OPEN) {
        wsClient.close();
        console.log("WebSocket连接已关闭");
    }
    
    // 更新UI状态
    startAndUploadButton.disabled = false;
    startAndUploadButton.textContent = "录音并上传";
    stopButton.disabled = true;
    playButton.disabled = false;
    
    // 启用下载按钮
    downloadWavButton.disabled = recordedPcmData.length === 0;
    downloadOpusButton.disabled = recordedOpusData.length === 0;
    
    statusLabel.textContent = `录音上传完成，共编码 ${window.totalOpusFramesEncoded} 帧，发送 ${recordedOpusData.length} 个Opus数据包`;
    
    console.log(`录音上传完成: 处理了 ${window.totalPcmSamplesProcessed} 个PCM样本，编码了 ${window.totalOpusFramesEncoded} 帧，发送了 ${recordedOpusData.length} 个Opus数据包`);
}

// 下载WAV文件
function downloadWavFile() {
    if (recordedPcmData.length === 0) {
        console.error("没有录音数据可下载");
        statusLabel.textContent = "错误：没有录音数据";
        return;
    }

    try {
        // 合并所有PCM数据
        let totalSamples = 0;
        recordedPcmData.forEach(data => {
            totalSamples += data.length;
        });

        const mergedPcmData = new Float32Array(totalSamples);
        let offset = 0;
        recordedPcmData.forEach(data => {
            mergedPcmData.set(data, offset);
            offset += data.length;
        });

        // 转换为Int16数据
        const int16Data = convertFloat32ToInt16(mergedPcmData);

        // 创建WAV文件
        const wavData = createWAVFile(int16Data, SAMPLE_RATE, CHANNELS);

        // 创建下载链接
        const blob = new Blob([wavData], { type: 'audio/wav' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `recording_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.wav`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);

        console.log(`WAV文件下载完成: ${a.download}`);
        statusLabel.textContent = `WAV文件下载完成: ${a.download}`;

    } catch (error) {
        console.error("下载WAV文件失败:", error);
        statusLabel.textContent = `下载WAV文件失败: ${error.message}`;
    }
}

// 下载OPUS文件
function downloadOpusFile() {
    if (recordedOpusData.length === 0) {
        console.error("没有OPUS数据可下载");
        statusLabel.textContent = "错误：没有OPUS数据";
        return;
    }

    try {
        // 创建OPUS文件（使用现有的OGG格式）
        const opusData = createCorrectOGGFile(recordedOpusData, SAMPLE_RATE, CHANNELS);

        // 创建下载链接
        const blob = new Blob([opusData], { type: 'audio/opus' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `recording_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.opus`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);

        console.log(`OPUS文件下载完成: ${a.download}`);
        statusLabel.textContent = `OPUS文件下载完成: ${a.download}`;

    } catch (error) {
        console.error("下载OPUS文件失败:", error);
        statusLabel.textContent = `下载OPUS文件失败: ${error.message}`;
    }
}
